package org.dcm4che3.tool.printscp;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.UUID;

import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Sequence;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.UID;
import org.dcm4che3.data.VR;
import org.dcm4che3.net.Association;
import org.dcm4che3.net.Commands;
import org.dcm4che3.net.Dimse;
import org.dcm4che3.net.Status;
import org.dcm4che3.net.pdu.PresentationContext;
import org.dcm4che3.net.service.AbstractDicomService;
import org.dcm4che3.net.service.DicomServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

public class FilmBoxService extends AbstractDicomService {

	private static final Logger log = LoggerFactory.getLogger(FilmBoxService.class);
	
	private static final String[] DISPLAY_FORMATS = { "STANDARD", "ROW", "COL" };
	
	private static final Map<String, JSONObject> FILM_BOX_MAP = new HashMap<>();
	
	private static final Map<String, JSONObject> FILM_BOX_MAP_AE = new HashMap<>();
	
	public FilmBoxService(String ... sopClass) {
		super(sopClass);
	}
	
	public static synchronized JSONObject getFilmbox(String sopRefInstanceUid) {
		return FILM_BOX_MAP.get(sopRefInstanceUid);
	}
	
	public static synchronized JSONObject getFilmboxAE(String sopRefInstanceUid) {
		return FILM_BOX_MAP_AE.get(sopRefInstanceUid);
	}
	
	public static void removeImgIdxFromFilmBox(String sopRefInstanceUid) {
		FILM_BOX_MAP.remove(sopRefInstanceUid);
	}
	
	@Override
	protected void onDimseRQ(Association as, PresentationContext pc, Dimse dimse, Attributes cmd, Attributes data)
			throws IOException {
		switch (dimse) {
        case N_CREATE_RQ:
            onNCreateRQ(as, pc, cmd, data);
            break;
        case N_DELETE_RQ:
        	onNDeleteRQ(as, pc, cmd, data);
            break;
        case N_SET_RQ:
            onNSetRQ(as, pc, cmd, data);
            break;
        case N_ACTION_RQ:
        	onNActionRQ(as, pc, cmd, data);
        	break;
        default:
        	log.error("not regnoize command={}", dimse);
            throw new DicomServiceException(Status.UnrecognizedOperation);
        }
	}
	
	protected void onNActionRQ(Association as, PresentationContext pc,
            Attributes rq, Attributes rqAttrs) throws IOException {
		Attributes rsp = Commands.mkNActionRSP(rq, Status.Success);
		as.tryWriteDimseRSP(pc, rsp, null);
	}
	
	protected void onNSetRQ(Association as, PresentationContext pc,
            Attributes rq, Attributes rqAttrs) throws IOException {
        Attributes rsp = Commands.mkNSetRSP(rq, Status.Success);
        Attributes rspAttrs = set(as, rq, rqAttrs, rsp);
        as.tryWriteDimseRSP(pc, rsp, rspAttrs);
    }
	
	protected void onNDeleteRQ(Association as, PresentationContext pc,
            Attributes rq, Attributes rqAttrs) throws IOException {
		Attributes rsp = Commands.mkNDeleteRSP(rq, Status.Success);
		as.tryWriteDimseRSP(pc, rsp, null);
	}
	
	protected void onNCreateRQ(Association as, PresentationContext pc,
            Attributes rq, Attributes rqAttrs) throws IOException {
	    Attributes rsp = Commands.mkNCreateRSP(rq, Status.Success);
	    Attributes rspAttrs = null;
	    if (!rq.getString(Tag.AffectedSOPClassUID).equals(UID.PresentationLUTSOPClass)) {
	    	rspAttrs  = create(as, rq, rqAttrs, rsp);
	    }
	    as.tryWriteDimseRSP(pc, rsp, rspAttrs);
	}
	
	protected Attributes create(Association as, Attributes rq,
	        Attributes rqAttrs, Attributes rsp) throws DicomServiceException {
		String imageDisplayFormat = rqAttrs.getString(Tag.ImageDisplayFormat);
		log.info("imageDisplayFormat==={}", imageDisplayFormat);
		log.info("film size==={}", rqAttrs.getString(Tag.FilmSizeID));
		log.info("FilmOrientation==={}", rqAttrs.getString(Tag.FilmOrientation));
		log.info("rqAttrs===={}", rqAttrs);
		int seqNum = extractRefSec(imageDisplayFormat);
		String remoteIp = as.getSocket().getInetAddress().getHostAddress();
		String remoteAe = as.getCallingAET();
		if (seqNum == -1) {
			log.error("invalid display format=====" + imageDisplayFormat);
		} else {
			createReferceIimageBoxSeq(remoteIp, remoteAe, rqAttrs, seqNum, imageDisplayFormat);
		}
    	return rqAttrs;
	}
	
	protected Attributes createReferceIimageBoxSeq(String remoteIp, String remoteAe, Attributes rqAttrs, int seqNum, String imageDisplayFormat) {
		Sequence imageBoxSeq = rqAttrs.newSequence(Tag.ReferencedImageBoxSequence, seqNum);
		Attributes value = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String randomInstanceSopUid = null;
		String filmBoxFolderName = sdf.format(new Date()) + File.separator + "filmbox-" + UUID.randomUUID().toString().replace("-", "");
		
		log.info("film box seqnum====={},filmBoxName={}", seqNum, filmBoxFolderName);

		for (int i = 0; i < seqNum; i++) {
			value = new Attributes();
			randomInstanceSopUid = getRandomInstanceSopUid();
			value.setBytes(Tag.ReferencedSOPClassUID, VR.UI, UID.BasicGrayscaleImageBoxSOPClass.getBytes());
			value.setBytes(Tag.ReferencedSOPInstanceUID, VR.UI, randomInstanceSopUid.getBytes());
			JSONObject filmBoxAttr = new JSONObject();
			filmBoxAttr.put("filmBoxName", filmBoxFolderName);
			filmBoxAttr.put("imageDisplayFormat", imageDisplayFormat);
			filmBoxAttr.put("filmSize", rqAttrs.getString(Tag.FilmSizeID));
			filmBoxAttr.put("filmOrientation", rqAttrs.getString(Tag.FilmOrientation));
			filmBoxAttr.put("createTime", System.currentTimeMillis());
			filmBoxAttr.put("imageBoxPosition", i+1);
			FILM_BOX_MAP.put(randomInstanceSopUid, filmBoxAttr);
			imageBoxSeq.add(value);
			
			FILM_BOX_MAP_AE.put(remoteIp+remoteAe, filmBoxAttr);
		}
		return rqAttrs;
	}
	
	private String getRandomInstanceSopUid() {
		Random r = new Random();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String randStr = String.valueOf(r.nextDouble()).substring(2,8);
		String uid = "1.2.689." + sdf.format(new Date()) + "." + randStr;
		return uid;
	}
	
	private int extractRefSec(String value) {
		for (String dis : DISPLAY_FORMATS) {
			if (value.startsWith(dis)) {
				String tmpStr = value.replace(dis, "").replace("\\", "");
				if (dis.equals("STANDARD")) {  //这个是相乘的，另外的是相加的
					return Integer.parseInt(tmpStr.split(",")[0]) * Integer.parseInt(tmpStr.split(",")[1]);
				} else {
					int total = 0;
					for (String v : tmpStr.split(",")) {
						total += Integer.parseInt(v);
					}
					return total;
				}
			}
		}
		return -1;
	}
	
	protected Attributes set(Association as, Attributes rq, Attributes rqAttrs,
            Attributes rsp) throws DicomServiceException {
    	log.info("set data===================film box");
        return null;
    }
}
